Single-origin adversarial load generator for authorized resilience testing. Rust. GPLv3. Linux.
Note much of this was written by AI, as always I have tested the code however there may still be some LLM driven problems in the code for professional traffic generation I would watch its log very carefully -unslept
Most load testers ask "how do you handle 10,000 happy shoppers." That is a useful question and it is not the one that takes your service down. OpenNetBench asks the other one. It throws the traffic real attackers throw. Slowloris holds, HTTP/2 rapid reset, connection-table exhaustion, raw SYN and ACK floods at line rate, and then it watches the target with an independent probe and tells you flat out whether the thing broke or held.
It runs sixteen vectors from L3 to L7 off a single box. No spoofing, no amplification, no botnet, no C2. One real source IP that you can trace and kill instantly. That is a deliberate design choice, not a limitation, and the reasoning is in docs/SAFETY.md.
This is not TRex. TRex hands you line-rate numbers and walks away. OpenNetBench hands you a verdict.
wrk, JMeter, Locust and friends model legitimate users. They tell you your throughput ceiling under polite traffic. None of them will hold ten thousand half-open connections until your worker pool starves, or open a stream and reset it before the server can breathe, or fill a home router's conntrack table in under a second. Those are the patterns that actually cause outages and those are the patterns this tool speaks.
The other half of the tool is the part nobody else bothers with. Generating load is easy. Knowing whether the target actually degraded, versus your own box running out of sockets, versus a WAF quietly eating the traffic, that is the hard part. OpenNetBench runs two independent observers against the target the whole time and classifies the outcome with a confidence and an evidence trail. It will not call a working rate limiter a "vuln" and it will not blame the target for your local port exhaustion.
The send path was measured at 25.6 million packets per second of 54-byte frames on a single desktop (Ryzen 7800X3D, 16 pinned shards, AF_PACKET plus batched sendmmsg with the qdisc bypassed). That is past 10GbE line rate. For anything up to and including a 10-gig target the tool is bound by the wire, not by the code.
That number matters because of the acceptance bar this was built against: crash a real home router in under thirty seconds. It does. On a live run the gateway went from answering to fully down in about six seconds, off state exhaustion, on wifi, nowhere near the code's ceiling.
Full breakdown, the harnesses, and every ceiling we hit is in docs/PERFORMANCE.md.
git clone https://github.com/UnsleptArch/OpenNetBench.git
cd OpenNetBench
./install.shThat builds the release binary and puts opennetbench on your PATH. It will also add ~/.local/bin to your shell profile if it is not already there, so a fresh shell just works.
./install.sh --system # machine-wide, /usr/local/bin, uses sudo
./install.sh --xdp # build the AF_XDP backend too (needs a capable NIC)
./install.sh --uninstall # remove itYou need the Rust toolchain (https://rustup.rs). Raw-socket vectors (syn_flood, ack_flood, icmp_flood) need sudo at run time.
Just want the binary, no PATH surgery:
cargo build --release # ./target/release/opennetbench# interactive, walks you through target, vectors, tuning, timing
opennetbench
# see what ships
opennetbench --list-presets
# let it probe the target, characterize it, recommend a combo, then run
opennetbench --auto --target example.com --duration 60
# one preset, one shot
opennetbench --preset web --target https://example.com --duration 60
# home router / gateway state exhaustion, raw sockets so sudo
sudo opennetbench --preset router --target 192.168.1.254 --duration 40
# build an editable plan without firing it, run it later
opennetbench --preset api --target https://api.example.com --save-config api.json
opennetbench --config api.jsonTargets are a URL or a bare IP. Bare IPs default to http:// because router and admin UIs are usually plaintext and the L4 vectors just want address:port. Hostnames default to https://.
Full flag and preset reference lives in docs/USAGE.md.
| Vector | Layer | What it does |
|---|---|---|
http_flood / https_only |
L7 | keep-alive HTTP/1.1 flood, rotating browser fingerprints |
range_flood |
L7 | CVE-2011-3192, a pile of overlapping Range headers |
slowloris |
L7 | incomplete headers held open, drains the connection pool |
rudy |
L7 | slow POST body, one byte at a time, ties up workers |
slow_read |
L7 | tiny receive window, pins the server's send buffer |
h2_flood |
L7 | multiplexed HTTP/2 request flood |
h2_rapid_reset |
L7 | CVE-2023-44487, open a stream and immediately reset it |
h2_continuation |
L7 | CVE-2024-27316, endless CONTINUATION frames with no end |
tls_exhaust |
L4/5 | repeat full TLS handshakes, cheap for you and expensive for them |
tcp_exhaust |
L4 | hold bare connections, exhaust the accept backlog / conn table |
syn_flood |
L4 | raw TCP SYN flood, real source IP (root) |
ack_flood |
L4 | raw ACK flood, beats on stateful firewalls and conntrack (root) |
udp_flood |
L4 | UDP flood, payload you pick |
dns_flood |
L7 | random-subdomain query flood |
icmp_flood |
L3 | ICMP echo flood (root) |
Deeper notes on each one, and why it hurts, are in docs/VECTORS.md.
An independent health probe TCP-connects to the target once a second the whole run, with a baseline taken before load starts. A second probe fires a real HTTP GET once a second when the app answered at baseline. The classifier reads both, plus the collapse curve (windowed p50/p95/p99 against load) and the HTTP status mix, and returns one of:
- MitigationEngaged — 429s from a rate limiter, or 403s with a WAF/CDN fingerprint. The defense is doing its job. Not a finding.
- Degrading / Down — p99 blows past baseline, or the probe stops answering. A real resource-exhaustion finding.
- EdgeBlocked — fast refusals, no application response.
- Healthy — the target ate it and kept going.
Confidence is capped at 0.9. It reports likelihood, never proof. It also knows the difference between the target dying and your own box running out of sockets, which is the mistake that makes most homegrown flooders lie to you.
Everything leaves one host. There is no agent protocol, no peer discovery, no remote control anywhere in the tree, and the raw vectors compute their checksums from the machine's real source IP so spoofing is not even wired up. Every run starts with a consent gate you have to type an exact phrase into at a real terminal, it cannot be satisfied by a flag or a pipe. Stop the process, stop the traffic. The full threat model is in docs/SAFETY.md.
This generates real denial-of-service load. Point it only at infrastructure you own or have written authorization to test. Doing otherwise is a crime under the Computer Fraud and Abuse Act (US), the Computer Misuse Act (UK), EU Directive 2013/40/EU, and the equivalent law wherever you are. The consent gate is not decoration and it is not legal cover either, that part is on you.
Good-faith authorized testing only. Your own systems, your lab, a CTF, or a client that hired you to hit them. Blah blah blah
- docs/USAGE.md — every flag, preset, and config knob
- docs/VECTORS.md — the sixteen vectors in detail
- docs/ARCHITECTURE.md — how the engine is built, module by module
- docs/PERFORMANCE.md — the fast path, the numbers, the benchmarking method
- docs/SAFETY.md — single origin, no spoofing, no C2, why it is built this way
GPLv3. See LICENSE.